package com.wanlian.net.File.worker;

import com.wanlian.File.FileUtils;
import com.wanlian.File.NetFileInfo;
import com.wanlian.net.core.ClientSocket;
import com.wanlian.net.core.Constants;
import com.wanlian.netty.model.NetFileInfoRecord;
import com.wanlian.netty.model.ResultInfo;
import com.wanlian.netty.msg.MsgType;
import com.wanlian.netty.msg.PeerMsg;
import com.wanlian.netty.msg.PeerMsgQueue;
import com.wanlian.netty.msg.ResultMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class DeviceClientFileWorker {
    private static Logger logger = LoggerFactory.getLogger(DeviceClientFileWorker.class);
    private static ClientSocket peer;
    private static Map<String, NetFileInfoRecord> netFileDir = new HashMap<>();
    private static Map<String, NetFileInfoRecord> readFileDir = new HashMap();
    private static Map<String, NetFileInfoRecord> needContinueDownFileDir = new HashMap<>();
    private static Map<String, NetFileInfoRecord> needContinueUpFileDir = new HashMap<>();


    public void work() {
        start();
        loadFile();
        sendThread();
        //keepConnect();
        sendContinueThread();
    }

    /**
     * 处理消息
     */
    private void start() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            TimeUnit.MILLISECONDS.sleep(10);
                            processMsg();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }

    private void loadFile() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            fixedThreadPool.execute(new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            TimeUnit.MILLISECONDS.sleep(20);
                            writeFile();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }

    private void sendContinueThread() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
        for (int i = 0; i < 5; i++) {
            fixedThreadPool.execute(new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            readContinueDownFile();
                            TimeUnit.MILLISECONDS.sleep(20);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }


    private void sendThread() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
        fixedThreadPool.execute(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        readFile();
                        TimeUnit.MILLISECONDS.sleep(20);
                        sendFile();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }


    private void keepConnect() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
        fixedThreadPool.execute(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(5000);
                        //检查peer的状态
                        peer.keepConnect();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    private synchronized void processMsg() {
        PeerMsg peerMsg = PeerMsgQueue.get();
    }


    /**
     * 需要重新下载的字节
     *
     * @param netFileinfos
     * @param clientId
     */
    private void continueDownFile(List<NetFileInfo> netFileinfos, String clientId) {
        //String filePath = "";
        String filePath = Constants.FILE_DIR + netFileinfos.get(0).getFileName();
        NetFileInfoRecord netFileInfoRecord = new NetFileInfoRecord();
        netFileInfoRecord.filePath = filePath;
        for (NetFileInfo item : netFileinfos) {
            item.setFilePath(filePath);
        }
        netFileInfoRecord.addAndTidy(netFileinfos);
        netFileInfoRecord.setClientId(clientId);
        boolean result = checkAndSendFile(clientId, netFileInfoRecord);
        if (result) {
            if (this.needContinueDownFileDir.containsKey(filePath) == false) {
                this.needContinueDownFileDir.put(filePath, netFileInfoRecord);
            }
        }
    }

    /**
     * 读取继续需要下载的文件
     */
    private synchronized void readContinueDownFile() {
        try {
            Thread.sleep(20);
            Map<String, NetFileInfoRecord> needRemoves = new HashMap<>();
            for (String item : needContinueDownFileDir.keySet()) {
                NetFileInfoRecord netFileInfoRecord = needContinueDownFileDir.get(item);
                if (netFileInfoRecord.getFileContinueRecord().isHasRead() && netFileInfoRecord.getNetFileInfos().size() == 0) {
                    needRemoves.put(item, netFileInfoRecord);
                    continue;
                } else {
                    netFileInfoRecord.readContinueFile();
                    List<NetFileInfo> tags = netFileInfoRecord.dequeue(100);
                    sendNetFileInfo(netFileInfoRecord.getClientId(), tags);
                }
            }
            for (String item : needRemoves.keySet()) {
                if (needContinueDownFileDir.containsKey(item)) {
                    needContinueDownFileDir.remove(item);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void sendNetFileInfo(String clientId, List<NetFileInfo> tags) {
        for (NetFileInfo nitem : tags) {
            System.out.println("currentIndex:" + nitem.getCurrentIndex() + "size:" + nitem.getSize());
            //nitem.transferToHBytes();
            nitem.setFileId(clientId);
            this.getPeer().sendFileData(nitem);
        }
    }


    private boolean checkAndSendFile(String clientId, NetFileInfoRecord netFileInfoRecord) {
        boolean isExist = FileUtils.isExist(netFileInfoRecord.filePath);
        if (!isExist) {
            ResultMsg resultMsg = new ResultMsg();
            resultMsg.setReplyType(MsgType.DEVICE_FILE_DOWNLOAD_REQ);
            ResultInfo resultInfo = new ResultInfo(false, "文件不存在");
            resultMsg.setResultInfo(resultInfo);
            resultMsg.setTagClientId(clientId);
            peer.sendSNData(resultMsg);
        }
        return isExist;
    }


    public void addToFileNeedDown(NetFileInfo netFileInfo, String clientId) {
        String filePath = Constants.FILE_DIR + netFileInfo.getFileName();
        NetFileInfoRecord netFileInfoRecord = new NetFileInfoRecord();
        netFileInfoRecord.setClientId(clientId);
        netFileInfoRecord.filePath = filePath;
        boolean result = checkAndSendFile(clientId, netFileInfoRecord);
        if (result) {
            if (this.readFileDir.containsKey(filePath) == false) {
                this.readFileDir.put(filePath, netFileInfoRecord);
            }
        }
    }

    private void addNetInfoRecord(NetFileInfo netFileInfo) {
        netFileInfo.transferToBytes();
        if (netFileDir.containsKey(netFileInfo.getFileName())) {
            netFileDir.get(netFileInfo.getFileName()).add(netFileInfo);
        } else {
            NetFileInfoRecord netFileInfoRecord = new NetFileInfoRecord();
            netFileInfoRecord.add(netFileInfo);
            netFileDir.put(netFileInfo.getFileName(), netFileInfoRecord);
        }
    }

    public synchronized void sendFile() throws InterruptedException {
        Thread.sleep(30);
        Map<String, String> needRemove = new HashMap<>();
        for (String item : readFileDir.keySet()) {
            NetFileInfoRecord netFileInfoRecord = readFileDir.get(item);
            List<NetFileInfo> netFileInfos = netFileInfoRecord.dequeue(100);
            if (netFileInfos.size() == 0 && netFileInfoRecord.bEnd) {
                needRemove.put(netFileInfoRecord.filePath, netFileInfoRecord.filePath);
            } else {
                sendNetFileInfo(netFileInfoRecord.getClientId(), netFileInfos);
            }
        }
        for (String item : needRemove.keySet()) {
            if (readFileDir.containsKey(item)) {
                readFileDir.remove(item);
            }
        }
    }

    private synchronized void readFile() throws InterruptedException {
        Thread.sleep(20);
        for (String item : readFileDir.keySet()) {
            NetFileInfoRecord netFileInfoRecord = readFileDir.get(item);
            if (netFileInfoRecord.bEnd) {
                continue;
            } else {
                netFileInfoRecord.readFile();
            }
        }
    }

    private synchronized void writeFile() {
        try {
            for (String key : netFileDir.keySet()) {
                NetFileInfoRecord netFileInfoRecord = netFileDir.get(key);
                if (netFileInfoRecord.getNetFileInfos().size() > 100) {
                    netFileInfoRecord.writeToFile(100);
                    peer.keepConnect();
                } else if (netFileInfoRecord.hasTimeout(200)) {
                    if (netFileInfoRecord.hasContent()) {
                        peer.keepConnect();
                        netFileInfoRecord.writeToFile(100);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ClientSocket getPeer() {
        return peer;
    }

    public void setPeer(ClientSocket peer) {
        this.peer = peer;
    }
}
